#!/usr/bin/python

from pymongo import MongoClient

client = MongoClient()
db = client['tut']
transactions = db['transactions']
accounts = db['accounts']

def transfer(source, destination, value):
    transactions.insert_one({"source":source, "destination":destination, "value":value, "status":"initial"})
    t = transactions.find_one({"status":"initial"})
    transactions.update_one({"_id":t["_id"]}, {"$set": {"status" : "pending"}})
    accounts.update_one({"name":t['source'], "pending":{"$ne":t['_id']}}, {"$inc": {"balance":-t["value"]}, "$push": {"pending":t["_id"]}})
    accounts.update_one({"name":t['destination'], "pending":{"$ne":t['_id']}}, {"$inc": {"balance":t["value"]}, "$push": {"pending":t["_id"]}})
    transactions.update_one({"_id":t["_id"]}, {"$set": {"status":"commited"}})
    accounts.update_one({"name":t["source"]}, {"$pull":{"pending":t["_id"]}})
    accounts.update_one({"name":t["destination"]}, {"$pull":{"pending":t["_id"]}})
    transactions.update_one({"_id":t["_id"]}, {"$set":{"status":"done"}})


def partial(source, destination, value):
    transactions.insert_one({"source":source, "destination":destination, "value":value, "status":"initial"})
    t = transactions.find_one({"status":"initial"})
    transactions.update_one({"_id":t["_id"]}, {"$set": {"status" : "pending"}})
    accounts.update_one({"name":t['source'], "pending":{"$ne":t['_id']}}, {"$inc": {"balance":-t["value"]}, "$push": {"pending":t["_id"]}})

def resume(source, destination, value):
    t = transactions.find_one({"status":"pending"})
    if t:
        accounts.update_one({"name":t['source'], "pending":{"$ne":t['_id']}}, {"$inc": {"balance":-t["value"]}, "$push": {"pending":t["_id"]}})
        accounts.update_one({"name":t['destination'], "pending":{"$ne":t['_id']}}, {"$inc": {"balance":t["value"]}, "$push": {"pending":t["_id"]}})
        transactions.update_one({"_id":t["_id"]}, {"$set": {"status":"commited"}})
        accounts.update_one({"name":t["source"]}, {"$pull":{"pending":t["_id"]}})
        accounts.update_one({"name":t["destination"]}, {"$pull":{"pending":t["_id"]}})
        transactions.update_one({"_id":t["_id"]}, {"$set":{"status":"done"}})

def rollback():
    t = transactions.find_one({"status":"pending"})
    if t:
        transactions.update_one({"_id":t["_id"]}, {"$set":{"status":"canceling"}})
        accounts.update_one({"name":t["source"], "pending":t["_id"]}, {"$inc":{"balance":t["value"]}, "$pull":{"pending":t["_id"]}})
        accounts.update_one({"name":t["destination"], "pending":t["_id"]}, {"$inc":{"balance":-t["value"]}, "$pull":{"pending":t["_id"]}})
        accounts.update_one({"name":t["source"]}, {"$pull":{"pending":t["_id"]}})
        accounts.update_one({"name":t["destination"]}, {"$pull":{"pending":t["_id"]}})
        transactions.update_one({"_id":t["_id"]}, {"$set":{"status":"canceled"}})



def initial():
    transactions.drop()
    accounts.drop()
    accounts.insert_one({"name":"A", "balance": 10000, "pending":[]})
    accounts.insert_one({"name":"B", "balance": 10000, "pending":[]})

partial("A", "B", 1000)
resume("A", "B", 1000)
#rollback()




